//
//  AVCaptureLowVersionViewController.m
//  CaptureDemo
//
//  Created by 苏沫离 on 2018/9/18.
//  Copyright © 2018年 苏沫离. All rights reserved.
//

#import "AVCaptureLowVersionViewController.h"

#import "AVCapturePreviewView.h"
#import <AVFoundation/AVFoundation.h>
#import "AVImageViewController.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import "UIImage+SampleBuffer.h"

@interface AVCaptureLowVersionViewController ()
<AVCapturePreviewViewDelegate>

@property (nonatomic ,strong) UIButton *recordButton;//拍照按钮
@property (nonatomic ,strong) UIButton *devicePositionButton;//镜头位置
@property (nonatomic ,strong) UIButton *flashModelButton;//闪光灯


@property (nonatomic ,strong) dispatch_queue_t sessionQueue;//配置AVCaptureSession的串行队列
@property (nonatomic ,strong) AVCaptureDeviceInput *videoDeviceInput;//数据源输入
@property (nonatomic ,strong) AVCaptureDevice *device;//硬件管理
@property (nonatomic ,strong) AVCaptureSession *session;//会话管理
@property (nonatomic ,strong) AVCaptureStillImageOutput *imgaeOutput;//输出管理
@property (nonatomic, strong) AVCapturePreviewView *previewView;//预览界面

@end

@implementation AVCaptureLowVersionViewController

#pragma mark - life cycle

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    /****   界面元素设置    ****/
    [self.view addSubview:self.previewView];
    [self.view addSubview:self.recordButton];
    [self.view addSubview:self.flashModelButton];
    [self.view addSubview:self.devicePositionButton];
    self.devicePositionButton.frame = CGRectMake(CGRectGetWidth(UIScreen.mainScreen.bounds) - (38 + 26 + 18), 0, 38 + 26 + 18, 26 + 24 + 10);
    self.flashModelButton.frame = CGRectMake(self.devicePositionButton.frame.origin.x - (18 + 20 + 18), 0, 18 + 20 + 18, 26 + 24 + 10);
    
    self.sessionQueue = dispatch_queue_create("com.CaptureDemo.sessionQueue", DISPATCH_QUEUE_SERIAL);
    [self getAuthorizationStatus];
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.navigationController.navigationBarHidden = YES;
    
    dispatch_async(self.sessionQueue, ^{
        [self.session startRunning];
    } );
}

- (void)viewDidDisappear:(BOOL)animated
{
    dispatch_async( self.sessionQueue, ^{
        [self.session stopRunning];
    });
    
    [super viewDidDisappear:animated];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - response click

- (void)recordButtonClick:(UIButton *)sender
{
    //imgaeOutput 此时没有捕获图像
    if (self.imgaeOutput.capturingStillImage == NO)
    {
        //获取指定连接
        AVCaptureConnection *stillImageConnection = [self.imgaeOutput connectionWithMediaType:AVMediaTypeVideo];
        
        //设置视频方向
        UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];
        AVCaptureVideoOrientation avcaptureOrientation = (AVCaptureVideoOrientation)curDeviceOrientation;
        if (curDeviceOrientation == UIDeviceOrientationLandscapeLeft){
            avcaptureOrientation = AVCaptureVideoOrientationLandscapeRight;
        }else if(curDeviceOrientation == UIDeviceOrientationLandscapeRight){
            avcaptureOrientation = AVCaptureVideoOrientationLandscapeLeft;
        }
        [stillImageConnection setVideoOrientation:avcaptureOrientation];
        
        //设置缩放比例，通过设置 AVCaptureDevice 的 videoZoomFactor 来实现
        //[stillImageConnection setVideoScaleAndCropFactor:effectiveScale];
        
        
        [self.imgaeOutput setOutputSettings:@{AVVideoCodecKey:AVVideoCodecJPEG}];
        [self.imgaeOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error) {
            NSLog(@"error --- %@ currentThread : %@",error,NSThread.currentThread);
            if (error){
                
            }
            else
            {
                NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                UIImage *image = [UIImage imageFromSampleBuffer:imageDataSampleBuffer];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.navigationController pushViewController:[[AVImageViewController alloc]initWithImage:image] animated:YES];
                });
                
                
                //写入相册
                CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
                [library writeImageDataToSavedPhotosAlbum:jpegData metadata:(__bridge id)attachments completionBlock:^(NSURL *assetURL, NSError *error) {
                    if (error) {
                        
                    }
                }];
                
                if (attachments)
                    CFRelease(attachments);
     
            }
        }];
    }
}

- (void)focusAndExposeTapLocation:(CGPoint)tapPoint
{
    dispatch_async( self.sessionQueue, ^{
        AVCaptureDevice *device = self.videoDeviceInput.device;
        NSError *error = nil;
        if ([device lockForConfiguration:&error] ) {
            
            /*
             设置(焦点/曝光)点不会启动(焦点/曝光)操作。
             调用set(焦点/曝光点)模式()来应用新的感兴趣点。
             */
            if ( device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus] ) {
                device.focusPointOfInterest = tapPoint;//焦点设置
                device.focusMode = AVCaptureFocusModeAutoFocus;//对焦模式设置
            }
            
            if ( device.isExposurePointOfInterestSupported && [device isExposureModeSupported:AVCaptureExposureModeAutoExpose] ) {
                device.exposurePointOfInterest = tapPoint;//曝光点设置
                device.exposureMode = AVCaptureExposureModeAutoExpose;//曝光模式设置
            }
            
            device.subjectAreaChangeMonitoringEnabled = YES;
            [device unlockForConfiguration];
        }
        else {
            NSLog( @"Could not lock device for configuration: %@", error );
        }
    });
}

//切换镜头位置
- (void)switchCameraLocationButtonClick
{
    self.recordButton.enabled = NO;
    self.devicePositionButton.enabled = NO;
    self.flashModelButton.enabled = NO;
    
    dispatch_async(self.sessionQueue, ^{
        
        if (@available(iOS 10.2, *)){
            
            AVCaptureDevice *currentVideoDevice = self.videoDeviceInput.device;
            AVCaptureDevicePosition currentPosition = currentVideoDevice.position;
            AVCaptureDevicePosition preferredPosition;
            AVCaptureDeviceType preferredDeviceType;
            
            switch (currentPosition)
            {
                case AVCaptureDevicePositionUnspecified:
                case AVCaptureDevicePositionFront:
                    preferredPosition = AVCaptureDevicePositionBack;
                    preferredDeviceType = AVCaptureDeviceTypeBuiltInDualCamera;
                    break;
                case AVCaptureDevicePositionBack:
                    preferredPosition = AVCaptureDevicePositionFront;
                    preferredDeviceType = AVCaptureDeviceTypeBuiltInWideAngleCamera;
                    break;
            }
            
            NSArray<AVCaptureDeviceType> *deviceTypes = @[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeBuiltInDualCamera];//设备类型：广角镜头、双镜头
            AVCaptureDeviceDiscoverySession *sessionDiscovery = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
            
            NSArray<AVCaptureDevice *> *devices = sessionDiscovery.devices;//当前可用的AVCaptureDevice集合
            __block AVCaptureDevice *newVideoDevice = nil;
            [devices enumerateObjectsUsingBlock:^(AVCaptureDevice * _Nonnull device, NSUInteger idx, BOOL * _Nonnull stop) {
                if ( device.position == preferredPosition && [device.deviceType isEqualToString:preferredDeviceType] ) {
                    newVideoDevice = device;
                    * stop = YES;
                }
            }];
            
            if (!newVideoDevice)
            {
                [devices enumerateObjectsUsingBlock:^(AVCaptureDevice * _Nonnull device, NSUInteger idx, BOOL * _Nonnull stop) {
                    if ( device.position == preferredPosition) {
                        newVideoDevice = device;
                        * stop = YES;
                    }
                }];
            }
            
            if (newVideoDevice)
            {
                AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:newVideoDevice error:NULL];
                
                [self.session beginConfiguration];
                
                //删除现有设备输入，因为不支持同时使用前后摄像头。
                [self.session removeInput:self.videoDeviceInput];
                
                if ( [self.session canAddInput:videoDeviceInput] ) {
                    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
                    
                    [self.session addInput:videoDeviceInput];
                    self.videoDeviceInput = videoDeviceInput;
                }
                else {
                    [self.session addInput:self.videoDeviceInput];
                }
                
                AVCaptureConnection *movieFileOutputConnection = [self.imgaeOutput connectionWithMediaType:AVMediaTypeVideo];
                if ( movieFileOutputConnection.isVideoStabilizationSupported ) {
                    movieFileOutputConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
                }
                [self.session commitConfiguration];
            }
            
        }
        else
        {
            AVCaptureDevice *currentVideoDevice = self.videoDeviceInput.device;
            AVCaptureDevicePosition currentPosition = currentVideoDevice.position;
            AVCaptureDevicePosition preferredPosition;
            
            switch (currentPosition)
            {
                case AVCaptureDevicePositionUnspecified:
                case AVCaptureDevicePositionFront:
                    preferredPosition = AVCaptureDevicePositionBack;
                    break;
                case AVCaptureDevicePositionBack:
                    preferredPosition = AVCaptureDevicePositionFront;
                    break;
            }
            
            //获取指定mediaType类型的AVCaptureDevice集合
            NSArray<AVCaptureDevice *> *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
            
            __block AVCaptureDevice *newVideoDevice = nil;
            //遍历所有可用的AVCaptureDevice，获取后置镜头
            [devices enumerateObjectsUsingBlock:^(AVCaptureDevice * _Nonnull device, NSUInteger idx, BOOL * _Nonnull stop) {
                if ( device.position == preferredPosition) {
                    newVideoDevice = device;
                    * stop = YES;
                }
            }];
            
            if ( newVideoDevice )
            {
                AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:newVideoDevice error:NULL];
                
                [self.session beginConfiguration];
                
                //删除现有设备输入，因为不支持同时使用前后摄像头。
                [self.session removeInput:self.videoDeviceInput];
                
                if ( [self.session canAddInput:videoDeviceInput] ) {
                    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
                    
                    [self.session addInput:videoDeviceInput];
                    self.videoDeviceInput = videoDeviceInput;
                }
                else {
                    [self.session addInput:self.videoDeviceInput];
                }
                
                AVCaptureConnection *movieFileOutputConnection = [self.imgaeOutput connectionWithMediaType:AVMediaTypeVideo];
                if ( movieFileOutputConnection.isVideoStabilizationSupported ) {
                    movieFileOutputConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
                }
                [self.session commitConfiguration];
            }
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.devicePositionButton.enabled = YES;
            self.flashModelButton.enabled = YES;
            self.recordButton.enabled = YES;
        } );
    });
    
}

//闪光灯模式：开 --> 关 --> 自动
- (void)flashModelButtonClick:(UIButton *)sender
{
    dispatch_async( self.sessionQueue, ^{
        AVCaptureDevice *device = self.videoDeviceInput.device;
        
        //是否有闪光灯，闪光灯当前是否可用：如果设备过热并需要冷却，闪光灯可能会变得不可用
        if (device.hasFlash == NO || device.flashAvailable == NO) {
            return ;
        }
        
        NSError *error = nil;
        if ([device lockForConfiguration:&error] ) {
            
            switch (device.flashMode){
                case AVCaptureFlashModeAuto:{
                    if ([device isFlashModeSupported:AVCaptureFlashModeOn]){
                        [device setFlashMode:AVCaptureFlashModeOn];
                        dispatch_async(dispatch_get_main_queue(), ^{
                            [sender setImage:resourceImage(@"cameraFlash_On") forState:UIControlStateNormal];
                        });
                    }
                }
                    break;
                case AVCaptureFlashModeOff:{
                    if ([device isFlashModeSupported:AVCaptureFlashModeAuto]){
                        [device setFlashMode:AVCaptureFlashModeAuto];
                        dispatch_async(dispatch_get_main_queue(), ^{
                            [sender setImage:resourceImage(@"cameraFlash_Auto") forState:UIControlStateNormal];
                        });
                    }
                    
                }
                    break;
                case AVCaptureFlashModeOn: {
                    if ([device isFlashModeSupported:AVCaptureFlashModeOff]){
                        [device setFlashMode:AVCaptureFlashModeOff];
                        dispatch_async(dispatch_get_main_queue(), ^{
                            [sender setImage:resourceImage(@"cameraFlash_Off") forState:UIControlStateNormal];
                        });
                    }
                }
                    break;
                default:
                    break;
            }
            
            [device unlockForConfiguration];
        }
        else {
            NSLog( @"Could not lock device for configuration: %@", error );
        }
    });    
}


#pragma mark - private method

- (void)getAuthorizationStatus
{
    switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
    {
        case AVAuthorizationStatusNotDetermined:
        {
            dispatch_suspend(self.sessionQueue);
            
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
             {
                 if (granted)
                 {
                     dispatch_resume(self.sessionQueue);
                     
                     dispatch_async(dispatch_get_main_queue(), ^{
                         [self configurationCaptureMethod];
                     });
                 }
                 NSLog(@"granted --- %d currentThread : %@",granted,NSThread.currentThread);
             }];
            NSLog(@"用户尚未授予或拒绝该权限:AVAuthorizationStatusNotDetermined");
        }
            break;
        case AVAuthorizationStatusRestricted:
            NSLog(@"不允许用户访问媒体捕获设备:AVAuthorizationStatusRestricted");
            break;
        case AVAuthorizationStatusDenied:
            NSLog(@"用户已经明确拒绝了应用访问捕获设备:AVAuthorizationStatusDenied");
            break;
        case AVAuthorizationStatusAuthorized:
            [self configurationCaptureMethod];
            NSLog(@"用户授予应用访问捕获设备的权限:AVAuthorizationStatusAuthorized");
            break;
        default:
            break;
    }
}

- (void)configurationCaptureMethod
{
    self.session = [[AVCaptureSession alloc] init];
    self.previewView.session = self.session;
    
    dispatch_async( self.sessionQueue, ^{
        
        [self.session beginConfiguration];
        
        AVCaptureDevice *videoDevice;
        if (@available(iOS 10.2, *))
        {
            videoDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInDualCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];
            if ( !videoDevice )
            {
                videoDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];
                
                if ( !videoDevice )
                {
                    videoDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
                }
            }
        }
        else
        {
            //返回的总是AVCaptureDeviceTypeBuiltInWideAngleCamera设备类型
            videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        }
        
        NSError *error = nil;
        
        AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
        if (!videoDeviceInput)
        {
            [self.session commitConfiguration];
            return;
        }
        
        
        if ( [self.session canAddInput:videoDeviceInput] )
        {
            [self.session addInput:videoDeviceInput];
            self.videoDeviceInput = videoDeviceInput;
            
            dispatch_async( dispatch_get_main_queue(), ^{
                
                //使用状态栏方向作为初始视频方向
                UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
                AVCaptureVideoOrientation initialVideoOrientation = AVCaptureVideoOrientationPortrait;
                if ( statusBarOrientation != UIInterfaceOrientationUnknown ) {
                    initialVideoOrientation = (AVCaptureVideoOrientation)statusBarOrientation;
                }
                
                self.previewView.videoPreviewLayer.connection.videoOrientation = initialVideoOrientation;
            } );
        }
        else
        {
            [self.session commitConfiguration];
            return;
        }
        
        
        
        AVCaptureStillImageOutput *imgaeOutput = [[AVCaptureStillImageOutput alloc] init];
        if ([self.session canAddOutput:imgaeOutput]){
            [self.session addOutput:imgaeOutput];
            self.imgaeOutput = imgaeOutput;
        }
        else
        {
            [self.session commitConfiguration];
            return;
        }
        
        [self.session commitConfiguration];
    });
}


- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
    
    if ( UIDeviceOrientationIsPortrait( deviceOrientation ) || UIDeviceOrientationIsLandscape( deviceOrientation ) ) {
        self.previewView.videoPreviewLayer.connection.videoOrientation = (AVCaptureVideoOrientation)deviceOrientation;
    }
}

#pragma mark - setter and getter

- (AVCapturePreviewView *)previewView
{
    if (_previewView == nil)
    {
        _previewView = [[AVCapturePreviewView alloc] initWithFrame:UIScreen.mainScreen.bounds];
        _previewView.delegate = self;
    }
    return _previewView;
}

- (UIButton *)flashModelButton
{
    if (_flashModelButton == nil)
    {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
        [button setImage:resourceImage(@"shanguangdeng") forState:UIControlStateNormal];
        button.imageEdgeInsets = UIEdgeInsetsMake(26, 0, 0, 0);
        [button addTarget:self action:@selector(flashModelButtonClick:) forControlEvents:UIControlEventTouchUpInside];
        
        _flashModelButton = button;
    }
    return _flashModelButton;
}

- (UIButton *)devicePositionButton
{
    if (_devicePositionButton == nil)
    {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button setImage:resourceImage(@"fanzhuan") forState:UIControlStateNormal];
        button.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
        button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
        button.imageEdgeInsets = UIEdgeInsetsMake(26, 0, 0, 38);
        [button addTarget:self action:@selector(switchCameraLocationButtonClick) forControlEvents:UIControlEventTouchUpInside];
        _devicePositionButton = button;
    }
    return _devicePositionButton;
}


- (UIButton *)recordButton
{
    if (_recordButton == nil)
    {
        _recordButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _recordButton.frame = CGRectMake(CGRectGetWidth(UIScreen.mainScreen.bounds) * 1/2.0 - 30,CGRectGetHeight(UIScreen.mainScreen.bounds) - 32 - 60, 60, 60);
        _recordButton.layer.backgroundColor = [UIColor.whiteColor colorWithAlphaComponent:0.7f].CGColor;;
        CAShapeLayer *backmMaskLayer = [CAShapeLayer layer];
        backmMaskLayer.frame = _recordButton.layer.bounds;
        backmMaskLayer.path = [UIBezierPath bezierPathWithRoundedRect:_recordButton.layer.bounds cornerRadius:(CGRectGetWidth(_recordButton.layer.frame) / 2.0)].CGPath;
        _recordButton.layer.mask = backmMaskLayer;
        
        
        CALayer *contentLayer = [CALayer layer];
        contentLayer.backgroundColor = UIColor.whiteColor.CGColor;
        contentLayer.frame = CGRectMake(4, 4, CGRectGetWidth(_recordButton.frame) - 8,  CGRectGetHeight(_recordButton.frame) - 8);
        CAShapeLayer *contentMaskLayer = [CAShapeLayer layer];
        contentMaskLayer.frame = contentLayer.bounds;
        contentMaskLayer.path = [UIBezierPath bezierPathWithRoundedRect:contentLayer.bounds cornerRadius:(CGRectGetWidth(contentLayer.frame) / 2.0)].CGPath;
        contentLayer.mask = contentMaskLayer;
        
        [_recordButton.layer addSublayer:contentLayer];
        
        [_recordButton addTarget:self action:@selector(recordButtonClick:) forControlEvents:UIControlEventTouchUpInside];
    }
    
    return _recordButton;
}

@end
